package controller

import (
	"fmt"
	"net/http"
	"strconv"
	
	"soma-server/common"
	"soma-server/model/system"
	"soma-server/pkg/e"
	r "soma-server/response"
	serviceSystem "soma-server/service/system"
	"soma-server/vo"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"github.com/thoas/go-funk"
)

type IRoleController interface {
	GetRoles(c *gin.Context)             // 获取角色列表
	GetRolesOptions(c *gin.Context)      // 获取角色下拉列表选项
	CreateRole(c *gin.Context)           // 创建角色
	UpdateRoleById(c *gin.Context)       // 更新角色
	GetRoleMenusById(c *gin.Context)     // 获取角色的权限菜单
	UpdateRoleMenusById(c *gin.Context)  // 更新角色的权限菜单
	GetRoleApisById(c *gin.Context)      // 获取角色的权限接口
	UpdateRoleApisById(c *gin.Context)   // 更新角色的权限接口
	BatchDeleteRoleByIds(c *gin.Context) // 批量删除角色
}

type RoleController struct {
	RoleService serviceSystem.IRoleService
}

func NewRoleController() IRoleController {
	roleService := serviceSystem.NewRoleService()
	roleController := RoleController{RoleService: roleService}
	return roleController
}

// 获取角色列表
func (rc RoleController) GetRoles(c *gin.Context) {
	var req vo.RoleListRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}

	// 获取角色列表
	roles, total, err := rc.RoleService.GetRoles(&req)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_LIST, nil, false)
		return
	}
	r.Response(c, http.StatusOK, e.SUCCESS_GET_ROLE_LIST, gin.H{
		"list":  roles,
		"total": total,
	}, true)
}

// 获取角色下拉列表选项
func (rc RoleController) GetRolesOptions(c *gin.Context) {
	// 获取角色下拉列表选项
	roles, err := rc.RoleService.GetRolesOptions()
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_OPTIONS, nil, false)
		return
	}
	r.Response(c, http.StatusOK, e.SUCCESS_GET_ROLE_OPTIONS, gin.H{
		"list": roles,
	}, true)
}

// 创建角色
func (rc RoleController) CreateRole(c *gin.Context) {
	var req vo.CreateRoleRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}

	// 获取当前用户最高角色等级
	uc := serviceSystem.NewUserService()
	_, _, ctxUser, err := uc.GetCurrentUserMinRoleSort(c)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_HIGHEST_ROLE_FAILED, nil, false)
		return
	}

	// 用户不能创建比自己等级高或相同等级的角色
	if req.Sort <= 1 {
		common.Log.Errorln("角色排序不能为1")
		r.Response(c, http.StatusBadRequest, e.ERROR_ROLE_SORT_CANNOT_BE_1, nil, false)
		return
	}

	role := system.Role{
		Name:    req.Name,
		Code:    req.Code,
		Remark:  &req.Remark,
		Status:  req.Status,
		Sort:    req.Sort,
		Creator: ctxUser.Username,
	}

	// 创建角色
	err = rc.RoleService.CreateRole(&role)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_CREATE_ROLE, nil, false)
		return
	}

	r.Response(c, http.StatusOK, e.SUCCESS_CREATE_ROLE, nil, true)

}

// 更新角色
func (rc RoleController) UpdateRoleById(c *gin.Context) {
	var req vo.UpdateRoleRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}
	// 获取path中的roleId
	roleId, _ := strconv.Atoi(c.Param("roleId"))
	if roleId <= 0 {
		common.Log.Errorln("获取角色id失败")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_ID_INCORRECT, nil, false)
		return
	}

	// 当前用户角色排序最小值（最高等级角色）以及当前用户
	ur := serviceSystem.NewUserService()
	minSort, currentRoleids, ctxUser, err := ur.GetCurrentUserMinRoleSort(c)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_HIGHEST_ROLE_FAILED, nil, false)
		return
	}

	// 不能更新比自己角色等级高或相等的角色
	// 根据path中的角色ID获取该角色信息
	roles, err := rc.RoleService.GetRolesByIds([]uint{uint(roleId)})
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_BY_ROLEID, nil, false)
		return
	}
	if len(roles) == 0 {
		common.Log.Errorln("未获取到角色信息")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_INFO, nil, false)
		return
	}
	if (minSort != 1 && roles[0].Sort == 1) || req.Sort == 1 {
		common.Log.Errorln("不能禁用 admin 角色")
		r.Response(c, http.StatusBadRequest, e.ERROR_CANNOT_DISABLED_ADMIN, nil, false)
		return
	}

	if req.Status == 2 && funk.Subset([]uint{req.ID}, currentRoleids) {
		common.Log.Errorln("不能禁用属于自己的角色")
		r.Response(c, http.StatusBadRequest, e.ERROR_CANNOT_UPDATE_ROLE_ITSELF, nil, false)
		return
	}

	role := system.Role{
		Name:    req.Name,
		Code:    req.Code,
		Remark:  &req.Remark,
		Status:  req.Status,
		Sort:    req.Sort,
		Updater: ctxUser.Username,
	}

	// 更新角色
	err = rc.RoleService.UpdateRoleById(uint(roleId), &role)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_ROLE, nil, false)
		return
	}

	// 如果更新成功，且更新了角色的Code, 则更新casbin中policy
	if req.Code != roles[0].Code {
		// 获取policy
		rolePolicies := common.CasbinEnforcer.GetFilteredPolicy(0, roles[0].Code)
		if len(rolePolicies) == 0 {
			common.Log.Errorln("获取casbin策略失败")
			r.Response(c, http.StatusOK, e.SUCCESS_UPDATE_ROLE, nil, true)
			return
		}
		rolePoliciesCopy := make([][]string, 0)
		// 替换Code
		for _, policy := range rolePolicies {
			policyCopy := make([]string, len(policy))
			copy(policyCopy, policy)
			rolePoliciesCopy = append(rolePoliciesCopy, policyCopy)
			policy[0] = req.Code
		}

		//gormadapter实现UpdatePolicies方法
		isUpdated, _ := common.CasbinEnforcer.UpdatePolicies(rolePoliciesCopy, rolePolicies)
		if !isUpdated {
			common.Log.Errorln("更新casbin策略失败")
			r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_ROLE_POLICYS, nil, false)
			return
		}

		err := common.CasbinEnforcer.LoadPolicy()
		if err != nil {
			common.Log.Errorln(err.Error())
			r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_ROLE_POLICYS, nil, false)
			return
		}

	}

	// 更新角色成功处理用户信息缓存有两种做法:（这里使用第二种方法，因为一个角色下用户数量可能很多，第二种方法可以分散数据库压力）
	// 1.可以帮助用户更新拥有该角色的用户信息缓存,使用下面方法
	// err = ur.UpdateUserInfoCacheByRoleId(uint(roleId))
	// 2.直接清理缓存，让活跃的用户自己重新缓存最新用户信息
	ur.ClearUserInfoCache()

	r.Response(c, http.StatusOK, e.SUCCESS_UPDATE_ROLE, nil, true)
}

// 获取角色的权限菜单
func (rc RoleController) GetRoleMenusById(c *gin.Context) {
	// 获取path中的roleId
	roleId, _ := strconv.Atoi(c.Param("roleId"))
	if roleId <= 0 {
		common.Log.Errorln("获取角色id失败")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_ID_INCORRECT, nil, false)
		return
	}
	RoleMenuIds, err := rc.RoleService.GetRoleMenusById(uint(roleId))
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_MENU_BY_ROLEID, nil, false)
		return
	}
	r.Response(c, http.StatusOK, e.SUCCESS_GET_ROLE_MENU_BY_ROLEID, gin.H{
		"list": RoleMenuIds,
	}, true)
}

// 更新角色的权限菜单
func (rc RoleController) UpdateRoleMenusById(c *gin.Context) {
	var req vo.UpdateRoleMenusRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}
	// 获取path中的roleId
	roleId, _ := strconv.Atoi(c.Param("roleId"))
	if roleId <= 0 {
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_ID_INCORRECT, nil, false)
		return
	}
	// 根据path中的角色ID获取该角色信息
	roles, err := rc.RoleService.GetRolesByIds([]uint{uint(roleId)})
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_BY_ROLEID, nil, false)
		return
	}
	if len(roles) == 0 {
		common.Log.Errorln("未获取到角色信息")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_INFO, nil, false)
		return
	}

	// 当前用户角色排序最小值（最高等级角色）以及当前用户
	ur := serviceSystem.NewUserService()
	minSort, _, ctxUser, err := ur.GetCurrentUserMinRoleSort(c)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_HIGHEST_ROLE_FAILED, nil, false)
		return
	}

	// 获取当前用户所拥有的权限菜单
	mr := serviceSystem.NewMenuService()
	// 根据用户ID获取用户的权限(可访问)菜单列表
	ctxUserMenus, err := mr.GetUserMenusByUserId(ctxUser.ID)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_MENU_TREE_BY_USERID, nil, false)
		return
	}

	// 获取当前用户所拥有的权限菜单ID
	ctxUserMenusIds := make([]uint, 0)
	for _, menu := range ctxUserMenus {
		ctxUserMenusIds = append(ctxUserMenusIds, menu.ID)
	}

	// 前端传来最新的MenuIds集合
	menuIds := req.MenuIds

	// 用户需要修改的菜单集合
	reqMenus := make([]*system.Menu, 0)

	// (非管理员)不能把角色的权限菜单设置的比当前用户所拥有的权限菜单多
	if minSort != 1 {
		isContains := true
		for _, id := range menuIds {
			if !funk.Contains(ctxUserMenusIds, id) {
				errStr := fmt.Sprintf("无权设置ID为%d的菜单", id)
				common.Log.Errorln(errStr)
				r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_MENU_DENY, nil, false)
				isContains = false
				return
			}
		}
		if !isContains {
			common.Log.Errorln("无权限设置接口")
			r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_APIS_DENY, nil, false)
			return
		}

		for _, id := range menuIds {
			for _, menu := range ctxUserMenus {
				copyMenu := menu
				if id == copyMenu.ID {
					reqMenus = append(reqMenus, copyMenu)
					break
				}
			}
		}
	} else {
		// 管理员随意设置
		if len(roles) != 0 && roles[0].Sort == 1 && ctxUser.Username != "admin" {
			common.Log.Errorln("没有权限更改 admin 角色菜单接口")
			r.Response(c, http.StatusBadRequest, e.ERROR_CANNOT_MODIFY_ADMIN_MENU, nil, false)
			return
		}
		// 根据menuIds查询查询菜单
		menus, err := mr.GetMenus()
		if err != nil {
			common.Log.Errorln(err.Error())
			r.Response(c, http.StatusBadRequest, e.ERROR_GET_MENU_LIST, nil, false)
			return
		}
		for _, menuId := range menuIds {
			for _, menu := range menus {
				copyMenu := menu
				if menuId == copyMenu.ID {
					reqMenus = append(reqMenus, copyMenu)
				}
			}
		}
	}

	roles[0].Menus = reqMenus

	err = rc.RoleService.UpdateRoleMenus(roles[0])
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_UPDATE_MENU_BY_ROLEID, nil, false)
		return
	}

	r.Response(c, http.StatusOK, e.SUCCESS_UPDATE_ROLE_MENU_BY_ROLEID, nil, true)

}

// 获取角色的权限接口
func (rc RoleController) GetRoleApisById(c *gin.Context) {
	// 获取path中的roleId
	roleId, _ := strconv.Atoi(c.Param("roleId"))
	if roleId <= 0 {
		common.Log.Errorln("获取角色id失败")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_ID_INCORRECT, nil, false)
		return
	}
	// 根据path中的角色ID获取该角色信息
	roles, err := rc.RoleService.GetRolesByIds([]uint{uint(roleId)})
	if err != nil || len(roles) == 0 {
		common.Log.Errorln("未获取到角色信息")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_BY_ROLEID, nil, false)
		return
	}
	// 根据角色 Code 获取 casbin 中 policy
	code := roles[0].Code
	apis, err := rc.RoleService.GetRoleApisByRoleKeyword(code)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_APIS_BY_ROLEID, nil, false)
		return
	}

	r.Response(c, http.StatusOK, e.SUCCESS_GET_ROLE_APIS_BY_ROLEID, gin.H{
		"list": apis,
	}, true)
}

// 更新角色的权限接口
func (rc RoleController) UpdateRoleApisById(c *gin.Context) {
	var req vo.UpdateRoleApisRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}

	// 获取path中的roleId
	roleId, _ := strconv.Atoi(c.Param("roleId"))
	if roleId <= 0 {
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_ID_INCORRECT, nil, false)
		return
	}
	// 根据path中的角色ID获取该角色信息
	roles, err := rc.RoleService.GetRolesByIds([]uint{uint(roleId)})
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_BY_ROLEID, nil, false)
		return
	}
	if len(roles) == 0 {
		common.Log.Errorln("未获取到角色信息")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_INFO, nil, false)
		return
	}

	// 当前用户角色排序最小值（最高等级角色）以及当前用户
	ur := serviceSystem.NewUserService()
	minSort, _, ctxUser, err := ur.GetCurrentUserMinRoleSort(c)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_HIGHEST_ROLE_FAILED, nil, false)
		return
	}

	// 获取当前用户所拥有的权限接口
	ctxRoles := ctxUser.Roles
	ctxRolesPolicies := make([][]string, 0)
	for _, role := range ctxRoles {
		copyRole := role
		policy := common.CasbinEnforcer.GetFilteredPolicy(0, copyRole.Code)
		// 深拷贝
		var copyPolicy = make([][]string, len(policy))
		for i:= range policy{
			copyPolicy[i] = make([]string,len(policy[i]))
			copy(copyPolicy[i],policy[i])
		}
		ctxRolesPolicies = append(ctxRolesPolicies, copyPolicy...)
	}

	// 得到path中的角色ID对应角色能够设置的权限接口集合
	for _, policy := range ctxRolesPolicies {
		// 修改是对内存中 casbin 规则的修改，所以上面要用到深拷贝，不然权限会出问题
		policy[0] = roles[0].Code
	}

	// 前端传来最新的ApiID集合
	apiIds := req.ApisIds
	// 根据apiID获取接口详情
	ar := serviceSystem.NewApiService()
	apis, err := ar.GetApisById(apiIds)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_API_BY_APIID, nil, false)
		return
	}
	// 生成前端想要设置的角色policies
	reqRolePolicies := make([][]string, 0)
	for _, api := range apis {
		copyApi := api
		reqRolePolicies = append(reqRolePolicies, []string{
			roles[0].Code, copyApi.Path, copyApi.Method,
		})
	}

	// (非管理员)不能把角色的权限接口设置的比当前用户所拥有的权限接口多
	if minSort != 1 {
		isContains := true
		for _, reqPolicy := range reqRolePolicies {
			if !funk.Contains(ctxRolesPolicies, reqPolicy) {
				errStr := fmt.Sprintf("无权设置路径为%s,请求方式为%s的接口", reqPolicy[1], reqPolicy[2])
				common.Log.Errorln(errStr)
				isContains = false
				return
			}
		}
		if !isContains {
			common.Log.Errorln("无权限设置接口")
			r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_APIS_DENY, nil, false)
			return
		}
	}

	if len(roles) != 0 && roles[0].Sort == 1 && ctxUser.Username != "admin" {
		common.Log.Errorln("没有权限更改 admin 角色权限接口")
		r.Response(c, http.StatusBadRequest, e.ERROR_CANNOT_MODIFY_ADMIN_API, nil, false)
		return
	}

	// 更新角色的权限接口
	err = rc.RoleService.UpdateRoleApis(roles[0].Code, reqRolePolicies)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_UPDATE_ROLE_API_BY_ROLEID, nil, false)
		return
	}

	r.Response(c, http.StatusOK, e.SUCCESS_UPDATE_ROLE_API_BY_ROLEID, nil, true)

}

// 批量删除角色
func (rc RoleController) BatchDeleteRoleByIds(c *gin.Context) {
	var req vo.DeleteRoleRequest
	// 参数绑定
	if err := c.ShouldBind(&req); err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.BINDING_PARAMS, nil, false)
		return
	}
	// 参数校验
	if err := common.Validate.Struct(&req); err != nil {
		errStr := err.(validator.ValidationErrors)[0].Translate(common.Trans)
		common.Log.Errorln(errStr)
		r.Response(c, http.StatusBadRequest, e.INVALID_PARAMS, nil, false)
		return
	}

	// 获取当前用户最高等级角色
	ur := serviceSystem.NewUserService()
	_, currentRoleids, _, err := ur.GetCurrentUserMinRoleSort(c)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_HIGHEST_ROLE_FAILED, nil, false)
		return
	}

	// 前端传来需要删除的角色ID
	roleIds := req.RoleIds
	// 获取角色信息
	roles, err := rc.RoleService.GetRolesByIds(roleIds)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_BY_ROLEID, nil, false)
		return
	}
	if len(roles) == 0 {
		common.Log.Errorln("未获取到角色信息")
		r.Response(c, http.StatusBadRequest, e.ERROR_GET_ROLE_INFO, nil, false)
		return
	}

	// 不能删除自己角色的角色
	for funk.Subset(req.RoleIds, currentRoleids) {
		common.Log.Errorln("不能删除属于自己的角色")
		r.Response(c, http.StatusBadRequest, e.ERROR_CANNOT_DELETE_ROLE_ITSELF, nil, false)
		return
	}

	// 删除角色
	err = rc.RoleService.BatchDeleteRoleByIds(roleIds)
	if err != nil {
		common.Log.Errorln(err.Error())
		r.Response(c, http.StatusBadRequest, e.ERROR_DELETE_ROLE, nil, false)
		return
	}

	// 删除角色成功直接清理缓存，让活跃的用户自己重新缓存最新用户信息
	ur.ClearUserInfoCache()
	r.Response(c, http.StatusOK, e.SUCCESS_DELETE_ROLE, nil, true)

}
